﻿using System;
using Gp.Scripts.Utils;
using QFramework;
using UnityEngine;

namespace Gp.Scripts.Character {
    /// <summary>
    /// 玩家角色动画控制器
    /// </summary>
    [RequireComponent(typeof(BaseCharacter))]
    public class SpriteCharacterAnimation : MonoBehaviour{
        [SerializeField] private Animator animator;
        [SerializeField] private BaseCharacter character;
        private SpriteRenderer _spriteRenderer;

        private void Reset() {
            this.animator = GetComponentInChildren<Animator>();
            this.character = this.GetComponent<SpriteCharacter>();
        }

        private void Start() {
            _spriteRenderer = animator.GetComponent<SpriteRenderer>();
            
            _sm = new FSM<AnimationState>();
            _sm.AddState(AnimationState.Run, new RunState(_sm, this));
            _sm.AddState(AnimationState.Walk, new WalkState(_sm, this));
            _sm.AddState(AnimationState.Idle, new IdleState(_sm, this));
            
            _sm.StartState(AnimationState.Idle);
        }


        private Vector3 Direction => character.characterState.forwardSpeed; 
        
        
        private void Update() {
            var input = Direction;
            var velocity = input.magnitude;
            var canRun = character.CanRun;
            
            if (velocity > 0.1f) {
                _sm.ChangeState(canRun ? AnimationState.Run : AnimationState.Walk);
            }
            else {
                _sm.ChangeState(AnimationState.Idle);
            }
            
            _sm.Update();
        }


        private int _curHash;
        private FSM<AnimationState> _sm;

        

        private enum  AnimationState{
            Idle,
            Walk,
            Run,
        }

        
        
        
        
        private class RunState : AbstractState<AnimationState, SpriteCharacterAnimation> {
            public RunState(FSM<AnimationState> fsm, SpriteCharacterAnimation target) : base(fsm, target) { }
            private static readonly int Name = Animator.StringToHash("Dash");
            private static readonly int Up =  Animator.StringToHash("DashUp");
            private static readonly int Down =  Animator.StringToHash("DashDown");

            
            private static readonly int Speed = Animator.StringToHash("Speed");
            private Animator _animator;
            protected override void OnEnter() {
                _animator = mTarget.animator;
            }

            protected override void OnUpdate() {
                int res = Process();
                if (mTarget._curHash == res)
                    return;

                mTarget._curHash = res;
                mTarget.animator.Play(res);
            }


            private int Process() {
                var direction = mTarget.Direction;
                float horizontal = direction.x;
                float vertical = direction.z;
                
                if (Math.Abs(horizontal) < 0.01f)
                    return vertical > 0 ? Up : Down;
                
                var face = horizontal > 0;
                this.mTarget._spriteRenderer.flipX = face;
                return Name;
            } 
        }
        
        
        private class WalkState : AbstractState<AnimationState, SpriteCharacterAnimation> {
            public WalkState(FSM<AnimationState> fsm, SpriteCharacterAnimation target) : base(fsm, target) { }
            private static readonly int Name = Animator.StringToHash("Walk");
            private static readonly int Up =  Animator.StringToHash("WalkUp");
            private static readonly int Down =  Animator.StringToHash("WalkDown");
            protected override void OnEnter() {
            }

            protected override void OnUpdate() {
                int res = Process();
                if (mTarget._curHash == res)
                    return;

                mTarget._curHash = res;
                mTarget.animator.Play(res);
            }


            private int Process() {
                var direction = mTarget.Direction;
                float horizontal = direction.x;
                float vertical = direction.z;
                
                if (Math.Abs(horizontal) < 0.01f)
                    return vertical > 0 ? Up : Down;
                
                var face = horizontal > 0;
                this.mTarget._spriteRenderer.flipX = face;
                return Name;
            } 
        }


        private class IdleState : AbstractState<AnimationState, SpriteCharacterAnimation> {
            public IdleState(FSM<AnimationState> fsm, SpriteCharacterAnimation target) : base(fsm, target) { }
            private static readonly int Name = Animator.StringToHash("Stop"); 
            
            
            protected override void OnEnter() {
                mTarget._curHash = Name;
                mTarget.animator.SetBool(Name, true);
            }

            protected override void OnExit() {
                mTarget.animator.SetBool(Name, false);
            }
        }
    }
    
}